<?php

namespace App\Models;

use Illuminate\Support\Str;
use Illuminate\Support\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class UserCoupon extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'title',
        'type_id',
        'type',
        'valid_at',
        'due_at',
        'used_at',
        'dealer_id',
        'org_id',
    ];

    protected $casts = [
        'type_id' => 'integer',
        'user_id' => 'integer',
        'org_id' => 'integer',
        'dealer_id' => 'integer',
    ];

    protected $dates = [
        'valid_at',
        'due_at',
        'used_at',
    ];

    const STATUS_UNUSED = 'unused';
    const STATUS_USED = 'used';
    const STATUS_OVERDUE = 'overdue';
    const STATUS_INEFFECTIVE = 'ineffective';

    public static $statusMap = [
        self::STATUS_UNUSED    => '待使用',
        self::STATUS_USED    => '已使用',
        self::STATUS_OVERDUE    => '已过期',
        self::STATUS_INEFFECTIVE    => '未生效',
    ];

    const TYPE_PRIZE = 'prize';

    public static $typeMap = [
        self::TYPE_PRIZE    => '抽奖',
    ];

    public function getStatusChAttribute()
    {
        return self::$statusMap[$this->status];
    }

    public function getStatusAttribute()
    {
        $now = Carbon::now();
        if ($this->used_at) {
            return self::STATUS_USED;
        } else if ($this->valid_at && Carbon::parse($this->valid_at)->gt($now)) {
            return self::STATUS_INEFFECTIVE;
        } else if ($this->due_at && Carbon::parse($this->due_at)->lt($now)) {
            return self::STATUS_OVERDUE;
        } else {
            return self::STATUS_UNUSED;
        }
    }

    public function scopeStatus($query, $status)
    {
        $now = Carbon::now()->toDateTimeString();
        switch ($status) {
            case self::STATUS_USED:
                return $query->whereNotNull('used_at');
                break;
            case self::STATUS_UNUSED:
                return $query
                    ->whereNull('used_at')
                    ->where(function ($query) use ($now) {
                        $query->whereNull('due_at')
                            ->orWhere('due_at', '>', $now);
                    });
                break;
            case self::STATUS_OVERDUE:
                return $query->where('due_at', '<', $now)->whereNull('used_at');
                break;
            default:
                return $query;
        }
    }

    public function scopeStart($query, $value)
    {
        if (empty($value)) {
            return $query;
        }
        return $query->where('created_at', '>=', $value);
    }

    public function scopeEnd($query, $value)
    {
        if (empty($value)) {
            return $query;
        }
        return $query->where('created_at', '<=', $value);
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    protected static function boot()
    {
        parent::boot();
        // 监听模型创建事件，在写入数据库之前触发
        static::creating(function ($model) {
            if (!$model->code) {
                $model->code = static::findAvailableCode();
                if (!$model->code) return false;
            }
        });
    }

    public static function findAvailableCode()
    {
        do {
            $code = strtoupper('CLU' . Str::random(7));
        } while (self::query()->where('code', $code)->exists());
        return $code;
    }

    public function dealer()
    {
        return $this->belongsTo(Dealer::class);
    }
}
